/***************************************************************************************************
  *Copyright(C),2010-2016,Sumscope
  *FileName	:  ZippedObjectMap.cpp
  *Author	:  scofined.qi
  *Version	:  1.0
  *Date		:  2020/06/04
  *Desc		:  //用于主要说明此程序文件完成的主要功能
  *Relation :  
  *Others	:  //其他内容说明
  *Function :  //主要函数列表，每条记录应包含函数名及功能简要说明
  *History	:  //修改历史记录列表，每条修改记录应包含修改日期、修改者及修改内容简介
***************************************************************************************************/
#include "ZippedObjectMap.h"
#include "BondInfo.h"
#include "CompanyReport.h"
#include <core/Utility.h>
#include <string>

#ifndef BASSERT
#define BASSERT //
#endif // !BASSERT

//TODO:
#define RTL_FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
#define FIELD_OFFSET(type, field)    offsetof(type, field)

//static_assert(sizeof(std::string) == 24, "");
ReportEncoder::FieldArray* ReportEncoder::FieldArray::Create(const char* src, const FieldOffset& fields)
{
	const std::vector<FieldInfo>& offsets = fields.m_fields;
	int headBytes = sizeof(ushort) + sizeof(ushort) + sizeof(Offset)*offsets.size();
	int bytes = headBytes;
	//vector<int>	sizes; sizes.reserve(offsets.size());
	qb::base::StackArray<int, 128> sizes;
	const int typeSize[kTypeCount] = { sizeof(char), sizeof(time_t),
        sizeof(int), sizeof(int64_t), sizeof(double), 0 };
	for (int i = 0; i < (int)offsets.size(); i++)
	{
		const FieldInfo& info = offsets[i];
		int encodeSize = typeSize[info.type];
		if (info.type == kTypeString)
			encodeSize = strlen(src + info.pos) + 1;
		if (IsDefault(src + info.pos, encodeSize))
			encodeSize = 0;
		bytes += encodeSize;
		sizes.Add(encodeSize);
	}
	
	char* buf = qb::base::EncodeBuf::Alloc(bytes);
	FieldArray* farray = (FieldArray*)buf;
	farray->m_count = offsets.size();
	farray->m_bytes = bytes;
	Offset* offs = farray->m_offsets;
	ushort pos = headBytes;
	for (int i = 0; i < farray->m_count; i++)
	{
		const FieldInfo& info = offsets[i];
		offs[i] = Offset(info.type, sizes[i] == 0 ? 1 : 0, pos);
		if (sizes[i] > 0)
			memcpy(buf + pos, src + info.pos, sizes[i]);
		pos += sizes[i];
	}
	BASSERT(pos == bytes);
	return farray;
}

void ReportEncoder::FieldArray::Destroy(FieldArray* farray)
{
	if (!farray)
		return;
	qb::base::EncodeBuf::Free((char*)farray);
}

bool ReportEncoder::FieldArray::Decode(const FieldArray* farray, char* dest, const FieldOffset& fields)
{
	const std::vector<FieldInfo>& offsets = fields.m_fields;
	if (farray->m_count != offsets.size())
		return false;

	memset(dest, 0, sizeof(REPORT));
	const char* src = (const char*)farray;
	const int typeSize[kTypeCount] = { sizeof(char), sizeof(time_t),
        sizeof(int), sizeof(int64_t), sizeof(double), 0 };

	for (int i = 0; i < (int)offsets.size(); i++)
	{
		const Offset& off = farray->m_offsets[i];
		const FieldInfo& info = offsets[i];
		if (off.dft == 1)	continue;
		//if (off.type == kTypeString)
		//	FIELDCOPYN(dest + info.pos, info.len, src + off.pos);
		//else
		//	memcpy(dest + info.pos, src + off.pos, typeSize[off.type]);
		switch (off.type)
		{
		case kTypeChar:dest[info.pos] = src[off.pos]; break;
		case kTypeTime:memcpy(dest + info.pos, src + off.pos, sizeof(time_t)); break;
		case kTypeInt:memcpy(dest + info.pos, src + off.pos, sizeof(int)); break;
        case kTypeInt64:memcpy(dest + info.pos, src + off.pos, sizeof(int64_t)); break;
		case kTypeDouble:memcpy(dest + info.pos, src + off.pos, sizeof(double)); break;
		case kTypeString:FIELDCOPYN(dest + info.pos, info.len, src + off.pos); break;
		}
	}
	return true;
}

void ReportEncoder::MetaInit::InitReport(FieldOffset* meta)
{
#define ADDFIELD(TYPE,OBJ,FIELD) \
				index=meta->Add(#FIELD,TYPE, FIELD_OFFSET(OBJ, FIELD), RTL_FIELD_SIZE(OBJ, FIELD))
#define ADDFIELD_EX(TYPE,OBJ,FIELD,POS) \
				index=meta->Add(#FIELD,TYPE, POS+FIELD_OFFSET(OBJ, FIELD), RTL_FIELD_SIZE(OBJ, FIELD))

	int index = 0;
	ADDFIELD(kTypeInt, REPORT, m_dwVersion);
	ADDFIELD(kTypeInt, REPORT, m_dwMarket);
	ADDFIELD(kTypeString, REPORT, m_sBondKey);
	ADDFIELD(kTypeString, REPORT, m_sListedMarket);
	ADDFIELD(kTypeTime, REPORT, m_time);
	ADDFIELD(kTypeTime, REPORT, m_create_time);
	ADDFIELD(kTypeString, REPORT, m_bp_status);
	ADDFIELD(kTypeString, REPORT, m_company_id);
	ADDFIELD(kTypeString, REPORT, m_price_status);

	BASSERT(index == (int)kReportField::PriceStatus);

	//两个PRICE结构体
	int pos = FIELD_OFFSET(REPORT, m_bidinfo);
	for (int i = 0; i < 2; i++)
	{
		ADDFIELD_EX(kTypeString, PRICE, m_id, pos);
		ADDFIELD_EX(kTypeString, PRICE, m_bp_status, pos);
		ADDFIELD_EX(kTypeString, PRICE, m_flag_bargain, pos);
		ADDFIELD_EX(kTypeString, PRICE, m_flag_relation, pos);
		ADDFIELD_EX(kTypeString, PRICE, m_flag_vip, pos);
		ADDFIELD_EX(kTypeString, PRICE, m_company_id, pos);
		ADDFIELD_EX(kTypeString, PRICE, m_flag_bad, pos);
		ADDFIELD_EX(kTypeString, PRICE, m_price_status, pos);
		ADDFIELD_EX(kTypeString, PRICE, m_rebate, pos);
		ADDFIELD_EX(kTypeString, PRICE, m_return_point, pos);
		ADDFIELD_EX(kTypeString, PRICE, m_clean_price, pos);
		ADDFIELD_EX(kTypeString, PRICE, m_yield_price, pos);
		ADDFIELD_EX(kTypeString, PRICE, m_sPrice, pos);
		ADDFIELD_EX(kTypeString, PRICE, m_quotetype, pos);
		ADDFIELD_EX(kTypeString, PRICE, m_sVolume, pos);
		ADDFIELD_EX(kTypeString, PRICE, m_description, pos);
		ADDFIELD_EX(kTypeString, PRICE, m_interpret, pos);
		ADDFIELD_EX(kTypeTime, PRICE, m_create_time, pos);
		ADDFIELD_EX(kTypeTime, PRICE, m_time, pos);
		pos = FIELD_OFFSET(REPORT, m_askinfo);
		BASSERT((i == 0 && index == (int)kReportField::Bid_time) ||
			(i == 1 && index == (int)kReportField::Ask_time));
	}

	BASSERT(index == (int)kReportField::Ask_time);
	// m_indx_info
	pos = FIELD_OFFSET(REPORT, m_indx_info);
	ADDFIELD_EX(kTypeString, INDX_PRICE, m_symbol, pos);
	ADDFIELD_EX(kTypeString, INDX_PRICE, m_price, pos);
	ADDFIELD_EX(kTypeString, INDX_PRICE, m_clean_price, pos);
	ADDFIELD_EX(kTypeString, INDX_PRICE, m_company_id, pos);
	ADDFIELD_EX(kTypeTime, INDX_PRICE, m_modify_time, pos);

	ADDFIELD(kTypeChar, REPORT, m_price_sel);
	ADDFIELD(kTypeString, REPORT, m_tradePrice);
	ADDFIELD(kTypeInt64, REPORT, m_pkg_id);
	BASSERT(index == (int)kReportField::PkgId);
}

char* ReportEncoder::Encode(const char* data, int size, int metaId, int& length)
{
	FieldArray* fa = FieldArray::Create(data, GetOffsets());
	length = fa->GetBytes();
	return (char*)fa;
}

int ReportEncoder::Decode(const void* encodedData, int encodedSize, char* rawData, int capcity)
{
	if (rawData && capcity >= sizeof(REPORT) &&
		FieldArray::Decode((const FieldArray*)encodedData, rawData, GetOffsets()))
		return sizeof(REPORT);
	return -1;
}
